package com.gitee.wsl.data.recycler

import com.gitee.wsl.data.recycler.RecyclerPool.WithPool
import kotlinx.atomicfu.AtomicRef
import kotlinx.atomicfu.atomic

/**
 * [RecyclerPool] implementation that uses
 * a lock free linked list for recycling instances.
 * Pool is unbounded: see [RecyclerPool] for
 * details on what this means.
 *
 *
 * NOTE: serious issues found with 2.17.0 lead to deprecation
 * of this implementation -- basically it is possible to have
 * unbalanced acquire/release success rate lead to excessive
 * growth of pooled instances.
 * See [
 * jackson-core#1260](https://github.com/FasterXML/jackson-core/issues/1260) for details.
 *
 */
//@Deprecated("Since 2.18: use other implementations")
// since 2.18
abstract class LockFreePoolBase<P : WithPool<P>>
protected constructor(serialization: Int) : StatefulImplBase<P>(serialization) {
    // Needs to be transient to avoid JDK serialization from writing it out

    private val head: AtomicRef<Node<P>?> = atomic(null)

    // // // Actual API implementation
    override fun acquirePooled(): P {
        // This simple lock free algorithm uses an optimistic compareAndSet strategy to
        // populate the underlying linked list in a thread-safe way. However, under very
        // heavy contention, the compareAndSet could fail multiple times, so it seems a
        // reasonable heuristic to limit the number of retries in this situation.
        for (i in 0..2) {
            val currentHead = head.value ?: return createPooled()
            if (head.compareAndSet(currentHead, currentHead.next)) {
                currentHead.next = null
                return currentHead.value
            }
        }
        return createPooled()
    }

    override fun releasePooled(pooled: P) {
        val newHead = Node(pooled)
        for (i in 0..2) {
            newHead.next = head.value
            if (head.compareAndSet(newHead.next, newHead)) {
                return
            }
        }
    }

    override fun pooledCount(): Int {
        var count = 0
        var curr = head.value
        while (curr != null) {
            ++count
            curr = curr.next
        }
        return count
    }

    // Yes, we can clear it
    override fun clear(): Boolean {
        head.value = null
        return true
    }

    protected class Node<P> internal constructor(val value: P) {
        var next: Node<P>? = null
    }

}


fun <P : WithPool<P>> RecyclerPool.Companion.lockFree(serialization: Int,createPooled:()->P)
        = object :LockFreePoolBase<P>(serialization){
    override fun createPooled(): P = createPooled()
}